﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

using SeriesManager.Enum;
using SeriesManager.Extension;
using SeriesManager.Model;
using SeriesManager.Model.Banner;
using SeriesManager.Core;
using WinRTFramework.Common;
using WinRTFramework.Interfaces.AppStates;

namespace SeriesManager.ViewModel
{
    public class SeasonViewModel : ViewModelBase, ISupportTransientState
    {
        #region Properties

        private ListViewSelectionMode selectionMode = ListViewSelectionMode.None;
        private SeasonModel season;

        public SeasonModel Season
        {
            get
            {
                return this.season;
            }
            private set
            {
                base.SetProperty<SeasonModel>(ref this.season, value);
            }
        }

        public ICollectionView View
        {
            get;
            private set;
        }

        public ListViewSelectionMode SelectionMode
        {
            get
            {
                return this.selectionMode;
            }
            private set
            {
                base.SetProperty<ListViewSelectionMode>(ref this.selectionMode, value);
            }
        }

        public ObservableCollection<EpisodeModel> SelectedItems 
        { 
            get; 
            private set; 
        }

        #endregion

        #region DelegateCommands

        public DelegateCommand<ItemClickEventArgs> SelectionAllCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> SelectionClearCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> SeasonStateCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> WatchStateCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> UnwatchStateCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> ItemClickedCommand
        {
            get;
            private set;
        }

        #endregion

        public SeasonViewModel()
        {
            this.SelectedItems = new ObservableCollection<EpisodeModel>();
            this.SelectedItems.CollectionChanged += SelectedItems_CollectionChanged;            

            this.SeasonStateCommand = new DelegateCommand<ItemClickEventArgs>(OnSeasonStateExecuted, OnSeasonStateCanExecute);
            this.ItemClickedCommand = new DelegateCommand<ItemClickEventArgs>(OnItemClickExecuted);
            this.WatchStateCommand = new DelegateCommand<ItemClickEventArgs>(OnWatchStateExecuted, OnWatchStateCanExecute);
            this.UnwatchStateCommand = new DelegateCommand<ItemClickEventArgs>(OnUnwatchStateExecuted, OnUnwatchStateCanExecute);
            this.SelectionClearCommand = new DelegateCommand<ItemClickEventArgs>(OnSelectionClearExecuted, OnSelectionClearCanExecute);
            this.SelectionAllCommand = new DelegateCommand<ItemClickEventArgs>(OnSelectionAllExecuted, OnSelectionAllCanExecute);
        }

        #region DelegateProperties

        private void OnSelectionAllExecuted(ItemClickEventArgs e)
        {
            foreach (var episode in this.season.Episodes)
            {
                if (!this.SelectedItems.Any(E => E.ID == episode.ID))
                {
                    this.SelectedItems.Add(episode);
                }
            }
        }

        private bool OnSelectionAllCanExecute(ItemClickEventArgs e)
        {
            return this.SelectedItems != null && this.season != null && this.season.Episodes.Any();
        }

        private void OnSelectionClearExecuted(ItemClickEventArgs e)
        {
            this.SelectedItems.Clear();
        }

        private bool OnSelectionClearCanExecute(ItemClickEventArgs e)
        {
            return this.SelectedItems.Any();
        }

        private void OnSeasonStateExecuted(ItemClickEventArgs e)
        {
            this.season.State = this.season.State.Invert();
            InvalidateCommands();
            base.NavigationBarIsOpen = this.SelectedItems.Any();
            TileManager.UpdateTile(this.season.Series.ID, this.season.Series.Unwatched.Count);
        }

        private bool OnSeasonStateCanExecute(ItemClickEventArgs e)
        {
            return this.season != null && this.season.Series.Subscription && this.season.Episodes.Any(E => E.State != WatchState.UnAired);
        }

        private void OnWatchStateExecuted(ItemClickEventArgs e)
        {
            for (int i = 0; i < this.SelectedItems.Count; i++)
            {
                if (this.SelectedItems[i].State == WatchState.Unwatched)
                {
                    this.SelectedItems[i].State = WatchState.Watched;
                    this.SelectedItems.RemoveAt(i);
                    i--;
                }
            }

            InvalidateCommands();
            TileManager.UpdateTile(this.season.Series.ID, this.season.Series.Unwatched.Count);
        }

        private bool OnWatchStateCanExecute(ItemClickEventArgs e)
        {
            return this.season != null && this.season.Series.Subscription && this.SelectedItems.Any(E => E.State == WatchState.Unwatched);
        }

        private void OnUnwatchStateExecuted(ItemClickEventArgs e)
        {
            for (int i = 0; i < this.SelectedItems.Count; i++)
            {
                if (this.SelectedItems[i].State == WatchState.Watched)
                {
                    this.SelectedItems[i].State = WatchState.Unwatched;
                    this.SelectedItems.RemoveAt(i);
                    i--;
                }
            }

            InvalidateCommands();
            TileManager.UpdateTile(this.season.Series.ID, this.season.Series.Unwatched.Count);
        }

        private bool OnUnwatchStateCanExecute(ItemClickEventArgs e)
        {
            return this.season != null && this.season.Series.Subscription && this.SelectedItems.Any(E => E.State == WatchState.Watched);
        }

        private void OnItemClickExecuted(ItemClickEventArgs e)
        {
            var clickedItem = (EpisodeModel)e.ClickedItem;
            base.NavigationService.Navigate<EpisodeViewModel>(clickedItem.ID);
        }

        #endregion

        private void SelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.SelectionAllCommand.NotifyCanExecuteChanged();
            this.SelectionClearCommand.NotifyCanExecuteChanged();
            this.WatchStateCommand.NotifyCanExecuteChanged();
            this.UnwatchStateCommand.NotifyCanExecuteChanged();
            base.NavigationBarIsOpen = this.SelectedItems.Any();
        }

        private void InvalidateCommands()
        {
            this.WatchStateCommand.NotifyCanExecuteChanged();
            this.UnwatchStateCommand.NotifyCanExecuteChanged();
        }

        public override void OnNavigatedTo(object navigationParameter)
        {
            base.OnNavigatedTo(navigationParameter);

            this.Season = AppX.Instance.Current.Seasons.FirstOrDefault(S => S.Number == (int)navigationParameter);
            if (this.season != null)
            {
                if (this.season.Series.Subscription && this.season.Episodes.Any(E => E.State != WatchState.UnAired))
                {
                    this.selectionMode = ListViewSelectionMode.Extended;
                }

                this.View = new CollectionViewSource() { Source = this.Season.Episodes }.View;
                base.OnPropertyChanged<ICollectionView>(() => this.View);
                this.SeasonStateCommand.NotifyCanExecuteChanged();
            }
        }

        public void UpdateTransientState(object state)
        {
            var collectionState = (CollectionViewState)state;
            foreach (int id in collectionState.SelectedItems)
            {
                var episode = this.season.Episodes.FirstOrDefault(E => E.ID == id);
                if (episode != null)
                {
                    this.SelectedItems.Add(episode);
                }
            }

            var currentItem = this.season.Episodes.FirstOrDefault(E => E.ID == collectionState.Position);
            if (currentItem != null)
            {
                this.View.MoveCurrentTo(currentItem);
            }
        }

        public object GetTransientState()
        {
            CollectionViewState state = new CollectionViewState();
            if (this.View != null && this.View.CurrentItem != null)
            {
                state.Position = (this.View.CurrentItem as EpisodeModel).ID;
            }
            state.SelectedItems = this.SelectedItems.Select(S => S.ID).ToArray();
            return state;
        }

        public System.Collections.Generic.IEnumerable<Type> GetTransientStateTypes()
        {
            yield return typeof(CollectionViewState);
        }
    }
}
